/*
 *Autor: Anderson Campos Cardoso
 *
 *Conteúdo: Arquivo que contém a implementação dos métodos da classe Audio
 */

#include "Audio.h"

#ifndef _AUDIO_CPP_
#define _AUDIO_CPP_

using namespace std;

/*
 *Inicia o subsistema de vídeo, criando a janela na memória da placa de vídeo
 */
void Audio::iniciaAudio(void)
{
   /*
    *A função SDL_Init() é usada para iniciar os subsistemas da SDL, deve ser chamada antes de
    *qualquer outra função SDL. retorna um valor negativo se ocorrer um problema.
    */
   if(SDL_Init(SDL_INIT_AUDIO) < 0)
   {
      cout << "Erro em Audio::iniciaAudio(void), ao iniciar subsistema de áudio\n" << Mix_GetError() << endl;
   }
   else
   {
      /*
       *Inicializa a biblioteca SDL_mixer
       *Mix_OpenAudio(
       *  frequencia = 'valor numérico'  frequencia da onda em Hertz
       *, formato    = 'AUDIO_S8' amostras com 8 bits | 'AUDIO_S16SYS' = 16 bits | 'MIX_DEFAULT_FORMAT' = padrão default
       *, channels   = 1 = mono | 2 = stereo
       *, chunksize  = valores entre 1024 e 4096, tamanho do buffer de saída
       *)
       */
      Mix_OpenAudio(44100, AUDIO_S16SYS, 2, 4096);
   }
}


/*
 *Carrega um arquivo de música no atributo musica
 */
void Audio::carregarMusica(string arquivoMusica)
{
   if (musica != NULL)
   {
      Mix_FreeMusic(musica);
      musica = NULL;
   }
   musica = Mix_LoadMUS(arquivoMusica.c_str());
}

/*
 *Altera o valor do volume da música
 */
void Audio::mudarVolumeMusica(int volume)
{
   /*
    *regula o volume da música
    *volume = 'int' volume da música varia de 0 e MIX_MAX_VOLUME(128), passe -1 para continuar com o volume atual
    */
   Mix_VolumeMusic(volume);
}

/*
 *Recebe como parâmetros o número de repetições da música o tempo de fade_in e volume da música a ser tocada
 */
void Audio::tocarMuscia(int loops, int fade_in, int volume)
{
   /*dá o play na música
    * Mix_FadeInMusic(
    *   musica  = '*Mix_Music' ponteiro para uma estrutura contendo o arquivo de música
    * , loops   = 'int' número de repetições da música(-1 toca infinitamente)
    * , fade_in = 'int' tempo em milisegindos para a múscia alcançar o seu volume total)
    */
   Mix_FadeInMusic(musica, loops, fade_in);
   mudarVolumeMusica(volume);
}

/*
 *Pausa uma música em execução
 */
void Audio::pausarMusica(void)
{
if(Mix_PlayingMusic())
    Mix_PauseMusic();
}

/*
 *Continua a tocar uma música pausada
 */
void Audio::continuarMusica(void)
{
if(Mix_PausedMusic())
    Mix_ResumeMusic();
}

/*
 *Reinicia a música, não funciona para arquivos .wav
 */
void Audio::reiniciarMusica(void)
{
   Mix_RewindMusic();
}

/*
 *Para uma música diminuindo gradualmente o volume da música
 */
void Audio::pararMusica(int fade_out)
{
   Mix_FadeOutMusic(fade_out);
}

/*
 * Se o canal não estiver sendo utilizado toca o som passado como parâmetro em um canal
 * específico repetidas vezes aumentando o volume gradualmente.
 * OBS: caso queira substituir o som do canal por outro som, este canal deve ser interrompido
 * através do método Audio::pararSomCanal() antes deste ser chamado.
 */
void Audio::tocarSomCanal(string nomeArquivo, int loops,int fade_in, int volume,int canal)
{
   if(!Mix_Playing(canal))
   {
      /*Caso haja algum  som no canal este é liberado*/
      if (vetorChunk[canal] != NULL)
      {
         Mix_FreeChunk(vetorChunk[canal]);
      }
      /*cria um novo som*/
      vetorChunk[canal] = Mix_LoadWAV(nomeArquivo.c_str());

      /*toca o som*/
      if(fade_in == 0)
      {
          Mix_PlayChannel(canal, vetorChunk[canal], loops);
      }
      else
      {
         Mix_FadeInChannel(canal, vetorChunk[canal], loops, fade_in);
      }
      /*Regula o volume do canal*/
      Mix_Volume(canal, volume);
   }
}

/*
 *Para de tocar o som de um canal gradualemnte diminuindo o volume durante 'fade_out' milisegundos
 *se o canal for -1 todos os canais são afetados
 */
void Audio::pararSomCanal(int canal, int fade_out)
{
   int i;
   if(Mix_Playing(canal))
   {
      if (fade_out != 0)
      {
         Mix_FadeOutChannel(canal, fade_out);
      }
      else
      {
         Mix_HaltChannel(canal);
      }
      /*
       *Loop que libera as regiões de memória apontado pelos ponteiros do vetorChunk.
       *Se canal for diferente de -1 libera apenas a região apontada pelo índice do canal
       */
      i = (canal == -1) ? 0 : canal;
      do{
         if ((vetorChunk[i] != NULL) )
         {
            Mix_FreeChunk(vetorChunk[i]);
            vetorChunk[i] = NULL;
         }
         i++;
      }while((canal== -1) && (i != QUANTIDADE_CANAIS));
   }
}


/*
 *Pausa um som que esteja sendo executado em um canal
 */
void Audio::pausarSomCanal(int canal)
{
   if (Mix_Playing(canal))
   {
      Mix_Pause(canal);
   }
}

/*
 *
 */
void Audio::continuarSomCanal(int canal)
{
   if (Mix_Paused(canal))
   {
      Mix_Resume(canal);
   }
}

/*
 *
 */
void Audio::tocarEfeitoSonoro(int canal, int loops, int fade_in, int volume)
{
   if(!Mix_Playing(canal))
   {
      /*Caso haja algum  som no canal este é tocado*/
      if (vetorChunk[canal] != NULL)
      {
         /*toca o som*/
         if(fade_in == 0)
         {
             Mix_PlayChannel(canal, vetorChunk[canal], loops);
         }
         else
         {
            Mix_FadeInChannel(canal, vetorChunk[canal], loops, fade_in);
         }
         /*Regula o volume do canal*/
         Mix_Volume(canal, volume);
      }
   }
}
/*
 *
 */
void Audio::pararEfeitoSonoro(int canal, int fade_out)
{
   if(Mix_Playing(canal))
   {
      if (fade_out != 0)
      {
         Mix_FadeOutChannel(canal, fade_out);
      }
      else
      {
         Mix_HaltChannel(canal);
      }
   }
}


/*
 *
 */
int Audio::alocarCanal(string nomeArquivo)
{
   int i;
   for (i= 0; (i<QUANTIDADE_CANAIS) && (vetorChunk[i] != NULL); i++);
   if(i<QUANTIDADE_CANAIS)
   {
      vetorChunk[i] = Mix_LoadWAV(nomeArquivo.c_str());
      return i;
   }
   else
      return -1;
}

/*
 *
 */
void Audio::desalocarCanal(int canal)
{
   if ((vetorChunk[canal] != NULL) )
   {
      Mix_FreeChunk(vetorChunk[canal]);
      vetorChunk[canal] = NULL;
   }
}

/*
 *Construtor da classe
 */
Audio::Audio(void){
   int i;
   musica = NULL;
   Mix_AllocateChannels(QUANTIDADE_CANAIS);
   for(i=0 ; i<QUANTIDADE_CANAIS; i++)
   {
       vetorChunk[i] = NULL;
   }
}


/*
 *Destrutor da classe
 */
Audio::~Audio(void){
   int i;
   Mix_CloseAudio();
   if (musica != NULL)
      Mix_FreeMusic(musica);
   for(i=0 ; i<QUANTIDADE_CANAIS; i++)
   {
       if (vetorChunk[i] != NULL)
          Mix_FreeChunk(vetorChunk[i]);
   }
}


#endif
